/**
 * 异步函数，用于请求视觉分析
 *
 * @param {string} imagePath - 图片URL地址
 *
 * @param {string} require - 可选的请求文本
 *
 * @param {string} imageData - 可选的base64格式图片数据
 *
 * @returns {Promise<Response>} - 包含分析结果的响应对象
 */
async function requestVisualAnalysis(imagePath, require, imageData) {
	/**
	 * 从服务器获取 文件服务 API 端点
	 */
	const FileUrl = await convertUrl(visualEndpointUrl.value, true);
	/**
	 * 构建完整图片URL
	 */
	const imageUrl = FileUrl + imagePath;
	/**
	 * 构建视觉请求内容
	 */
	const visualContent = await createVisualContent(imageUrl, require, imageData);
	/**
	 * 构建消息数组
	 */
	const messages = [
		{ role: "user", content: visualContent },
		{ role: "user", content: "/no_thinking" }
	];
	// 发送请求并返回响应
	return contactReasoningModel(visualEndpointUrl, visualEndpointKey, visualModelDropdown, messages, true, true);
};

/**
 * 构建视觉请求内容
 *
 * @param {string} imageUrl - 图片URL
 *
 * @param {string} prompt - 可选的请求文本
 *
 * @param {string} imageData - 可选的base64格式图片数据
 *
 * @returns {Promise<Array>} - 包含图片请求项和可选文本请求项的数组
 */
async function createVisualContent(imageUrl, prompt, imageData) {
	/**
	 * 从服务器获取 图片分析提示 文本
	 */
	const markdown = await fetchMarkdown('./prompt/imagePrompt.md');
	/**
	 * 构建图片请求项
	 */
	const imageContent = { type: "image_url", image_url: { url: imageData || imageUrl } };
	/**
	 * 构建文本请求项
	 */
	const textContent = { type: "text", text: markdown + prompt };
	// 返回包含图片请求项和可选文本请求项的数组
	return [textContent, imageContent];
};

/**
 * 将图片文件转换为Base64编码的字符串
 *
 * @param {File} file - 图片文件对象
 *
 * @returns {Promise<string>} - 包含Base64编码字符串的Promise
 */
function convertImageToBase64(file) {
	return new Promise(
		(resolve, reject) => {
			/**
			 * 创建FileReader实例，用于读取文件
			 */
			const reader = new FileReader();
			// 为FileReader的onload事件添加回调，读取成功时返回Base64编码结果
			reader.onload = () => resolve(reader.result);
			// 为FileReader的onerror事件添加回调，读取失败时抛出错误
			reader.onerror = (error) => reject(error);
			// 以DataURL格式读取文件
			reader.readAsDataURL(file);
		}
	);
}

/**
 * 将Base64编码的字符串转换为图片文件
 *
 * @param {string} base64String - Base64编码的字符串（必须包含前缀）
 *
 * @param {string} [fileName='image'] - 生成的文件名（不含扩展名）
 *
 * @returns {File} - 包含图片文件对象
 *
 * @throws {Error} 当Base64图片字符串格式无效时抛出错误
 */
function convertBase64ToImageFile(base64String, fileName = 'image') {
	try {
		/**
		 * 将Base64字符串按逗号分割，分离出头部信息和实际数据
		 */
		const [header, data] = base64String.split(',');
		/**
		 * 从头部信息中提取MIME类型
		 */
		const mimeType = header.match(/:(.*?);/)[1];
		/**
		 * 对Base64编码的数据进行解码，将其转换为原始的字节数据
		 */
		const byteCharacters = atob(data);
		/**
		 * 创建一个Uint8Array数组，用于存储解码后的字节数据
		 */
		const byteNumbers = new Uint8Array(byteCharacters.length);
		// 将解码后的字符转换为对应的字节数值
		for (let i = 0; i < byteCharacters.length; i++) {
			byteNumbers[i] = byteCharacters.charCodeAt(i);
		}
		// 创建一个新的File对象，使用解码后的字节数据、文件名和MIME类型
		return new File([byteNumbers], `${fileName}.${mimeType.split('/')[1]}`, { type: mimeType });
	}
	catch (error) {
		// 当Base64字符串格式无效时，抛出错误提示
		throw new Error('无效的Base64图片字符串格式');
	}
};

/**
 * 异步函数，用于将图片文件保存到服务器，使用内容哈希作为文件名
 *
 * @param {File} file - 需要保存的图片文件对象
 *
 * @returns {Promise<string>} - 保存成功后返回图片的读取路径，失败则抛出错误
 */
async function saveImageToServer(file) {
	try {
		/** 计算文件的SHA-256哈希值（取前16个字符，保持较短长度） */
		const fileHash = await calculateFileHash(file);
		/** 获取文件扩展名 */
		const fileExtension = file.name.slice(file.name.lastIndexOf('.')).toLowerCase();
		/** 使用哈希值 + 扩展名作为新文件名 */
		const newFileName = `${fileHash}${fileExtension}`;
		/** 将包含图片文件名的路径进行 Base64 编码，用于设置请求头中的文件名 */
		const base64FileName = toBtoaString('images/' + newFileName);
		/** 向服务器发送 POST 请求，尝试保存图片文件 */
		const response = await fetch('/save', { method: 'POST', headers: { 'X-File-Name': base64FileName, 'X-Overwrite': 'true' }, body: file });
		// 检查响应是否成功，若失败则抛出错误
		if (!response.ok) throw new Error('图片保存失败');
		// 保存成功，返回图片的读取路径
		return `/read/images/${newFileName}`;
	}
	catch (error) {
		// 捕获异常并显示错误信息
		showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
	}
};

/**
 * 异步函数，用于计算文件的SHA-256哈希值，并截取前16个字符
 *
 * @param {File} file - 文件对象
 *
 * @returns {Promise<string>} - 16字符的十六进制哈希值
 */
async function calculateFileHash(file) {
	/** 定义处理文件读取的异步函数 */
	function process(resolve) {
		/** 创建FileReader实例，用于读取文件内容 */
		const reader = new FileReader();
		// 为FileReader的onload事件添加回调函数，文件读取成功时触发
		reader.onload = async function (e) {
			try {
				/** 从FileReader事件对象中获取文件的ArrayBuffer数据 */
				const arrayBuffer = e.target.result;
				/** 使用crypto.subtle.digest方法计算ArrayBuffer的SHA-256哈希值 */
				const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
				/** 将哈希结果的ArrayBuffer转换为Uint8Array数组 */
				const hashArray = Array.from(new Uint8Array(hashBuffer));
				/** 将Uint8Array数组中的每个字节转换为两位的十六进制字符串，并拼接成完整的哈希字符串 */
				const fullHash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
				/** 截取完整哈希字符串的前16个字符 */
				const shortHash = fullHash.substring(0, 16);
				// 将截取后的短哈希值作为Promise的成功结果返回
				resolve(shortHash);
			}
			catch (error) {
				// 捕获计算哈希过程中出现的错误，并显示系统消息
				showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
			}
		};
		// 为FileReader的onerror事件添加回调函数，文件读取失败时触发
		reader.onerror = () => {
			// 显示文件读取失败的系统消息
			showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
		};
		// 以ArrayBuffer格式读取文件内容
		reader.readAsArrayBuffer(file);
	};
	// 返回一个Promise，用于处理异步操作
	return new Promise(process);
}